package com.jboltai.resource.ai;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.jboltai.capability.model.AIEventProcessor;
import com.jboltai.capability.model.ali.QianwenAIImpl;
import com.jboltai.capability.model.baichuan.BaichuanAIImpl;
import com.jboltai.capability.model.baidu.WenxinAIImpl;
import com.jboltai.capability.model.claude.ClaudeAIImpl;
import com.jboltai.capability.model.deepseek.DeepseekAIImpl;
import com.jboltai.capability.model.doubao.DoubaoAIImpl;
import com.jboltai.capability.model.glm.GLM4AIImpl;
import com.jboltai.capability.model.lmstudio.LMStudioAIImpl;
import com.jboltai.capability.model.local.LocalAIImpl;
import com.jboltai.capability.model.moonshot.MoonshotAIImpl;
import com.jboltai.capability.model.ollama.OllamaAIImpl;
import com.jboltai.capability.model.openai.ChatgptAIImpl;
import com.jboltai.capability.model.siliconflow.SiliconflowAIImpl;
import com.jboltai.capability.model.vllm.VLLMAIImpl;
import com.jboltai.capability.model.xinghuo.XingHuoAIImpl;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

/**
 * ai大模型
 */
public class AIModel {
    /**
     * 星火
     */
    public static final String SN_XINGHUO = "xinghuo";
    /**
     * 豆包
     */
    public static final String SN_DOUBAO = "doubao";

    /**
     * 百川2
     */
    public static final String SN_BAICHUAN = "baichuan";
    public static final String SN_BAICHUAN2 = "baichuan2";

    /**
     * OpenAI的chatgpt3.5
     */
    public static final String SN_CHATGPT35 = "chatgpt3.5";

    /**
     * OpenAI的chatgpt4
     */
    public static final String SN_CHATGPT4 = "chatgpt4";

    /**
     * 阿里通义千问
     */
    public static final String SN_QIANWEN = "qianwen";

    /**
     * 文心一言大模型
     */
    public static final String SN_WENXIN = "wenxin";

    /**
     * moonshot大模型
     */
    public static final String SN_MOONSHOT = "moonshot";

    /**
     * deepseek深度探索大模型
     */
    public static final String SN_DEEPSEEK = "deepseek";

    /**
     * 本地大模型
     */
    public static final String SN_LOCAL_MODEL = "local_model";

    /**
     * OLLAMA
     */
    public static final String SN_OLLAMA = "ollama";
    public static final String SN_VLLM = "vLLM";
    /**
     * 智普
     */
    public static final String SN_GLM = "glm";

    /**
     * Claude大模型
     */
    public static final String SN_CLAUDE = "claude";

    /**
     * 硅基流动
     */
    public static final String SN_SILICONFLOW = "siliconflow";

    /**
     * LM STUDIO
     */
    public static final String SN_LM_STUDIO = "lm_studio";

    /**
     * 根据模型类型，获取模型对象
     *
     * @param sn
     * @return
     */
    public static AIModel get(String sn) {
        switch (sn) {
            case SN_DOUBAO:
                return DOU_BAO;
            case SN_CLAUDE:
                return CLUADE;
            case SN_BAICHUAN:
                return BAI_CHUAN;
            case SN_CHATGPT35:
                return CHATGPT_4;
            case SN_CHATGPT4:
                return CHATGPT_4;
            case SN_QIANWEN:
                return QIAN_WEN;
            case SN_WENXIN:
                return WEN_XIN;
            case SN_MOONSHOT:
                return MOONSHOT;
            case SN_OLLAMA:
                return OLLAMA;
            case SN_LOCAL_MODEL:
                return LOCAL_MODEL;
            case SN_DEEPSEEK:
                return DEEP_SEEK;
            case SN_XINGHUO:
                return XING_HUO;
            case SN_GLM:
                return GLM;
            case SN_VLLM:
                return vLLM;
            case SN_SILICONFLOW:
                return SILICONFLOW;
            case SN_LM_STUDIO:
                return LM_STUDIO;
            default:
                return null;
        }
    }


    /**
     * 列出所有支持的模型类型
     * @return
     */
    public static List<AIModel> listAll() {
        return Arrays.asList(
                DEEP_SEEK,
                QIAN_WEN,
                CLUADE,
                CHATGPT_4,
                MOONSHOT,
                SILICONFLOW,
                OLLAMA,
                vLLM,
                LM_STUDIO,
                BAI_CHUAN,
                DOU_BAO,
                GLM,
                XING_HUO,
                WEN_XIN,
                LOCAL_MODEL
                );
    }


    /**
     * Claude大模型，默认使用claude-3-5-haiku-20241022
     */
    public static final AIModel CLUADE = new AIModel(SN_CLAUDE, "Claude", ClaudeAIImpl.INSTANCE, "claude-3-5-haiku-latest")
            .setConfigItems(model -> (new ConfigItem[]{
                    ConfigItem.ofDefaultModel(false, "默认大模型为：" + model.getDefaultModel()),
                    ConfigItem.ofApiKey(true, null),
                    ConfigItem.ofApiUrl(false, "Claude推荐使用海外代理服务进行请求")
            }));

    /**
     * 百川2大模型，默认使用Baichuan2-Turbo
     */
    public static final AIModel BAI_CHUAN = new AIModel(SN_BAICHUAN,  "百川智能",  BaichuanAIImpl.INSTANCE,  "Baichuan4-Turbo")
            .setConfigItems(model -> new ConfigItem[]{
                    ConfigItem.ofDefaultModel(false, "默认大模型为：" + model.getDefaultModel()),
                    ConfigItem.ofApiKey(true, null),
                    ConfigItem.ofApiUrl(false, null)
            });

    /**
     * 星火大模型
     */
    public static final AIModel XING_HUO = new AIModel(SN_XINGHUO, "讯飞星火",  XingHuoAIImpl.INSTANCE, "generalv3.5")
            .setConfigItems(model -> new ConfigItem[]{
                    ConfigItem.ofDefaultModel(false, "默认大模型为：" + model.getDefaultModel()),
                    ConfigItem.ofApiKey(true, "使用http服务的APIPassword值"),
                    ConfigItem.ofApiUrl(false, null)
            });

    /**
     * 豆包大模型
     */
    public static final AIModel DOU_BAO = new AIModel(SN_DOUBAO, "豆包大模型",  DoubaoAIImpl.INSTANCE, null).setImageInput(true)
            .setConfigItems(model -> new ConfigItem[]{
                    ConfigItem.ofDefaultModel(true, "豆包大模型必须设置该值，并且需要设置为推理接入点的id，详情查看文档：https://www.volcengine.com/docs/82379/1298454"),
                    ConfigItem.ofApiKey(true, null),
                    ConfigItem.ofApiUrl(false, null)
            });
    /**
     * chatgpt 4大模型，默认使用gpt-4-0125-preview
     */
    public static final AIModel CHATGPT_4 = new AIModel(SN_CHATGPT4,  "ChatGPT", ChatgptAIImpl.INSTANCE, "gpt-4o")
            .setImageInput(true).setConfigItems(model -> new ConfigItem[]{
                    ConfigItem.ofDefaultModel(false, "默认大模型为：" + model.getDefaultModel()),
                    ConfigItem.ofApiKey(true, null),
                    ConfigItem.ofApiUrl(false, "CHATGPT推荐使用海外代理服务进行请求")
            });

    /**
     * DeepSeek大模型，默认使用deepseek-chat
     */
    public static final AIModel DEEP_SEEK = new AIModel(SN_DEEPSEEK, "DeepSeek",  DeepseekAIImpl.INSTANCE, "deepseek-chat")
            .setConfigItems(model -> new ConfigItem[] {
                    ConfigItem.ofDefaultModel(false, "默认大模型为：" + model.getDefaultModel()),
                    ConfigItem.ofApiKey(true, null),
                    ConfigItem.ofApiUrl(false, null)
            });

    /**
     * 阿里的通义千问大模型，默认使用 qwen-max
     */
    public static final AIModel QIAN_WEN = new AIModel(SN_QIANWEN,  "通义千问", QianwenAIImpl.INSTANCE, "qwen-max-latest")
            .setImageInput(true).setConfigItems(model -> new ConfigItem[]{
                    ConfigItem.ofDefaultModel(false, "默认大模型为：" + model.getDefaultModel()),
                    ConfigItem.ofApiKey(true, null),
                    ConfigItem.ofApiUrl(false, null)
            });

    /**
     * 百度文心一言大模型
     */
    public static final AIModel WEN_XIN = new AIModel(SN_WENXIN,  "文心一言", WenxinAIImpl.INSTANCE, "ernie-4.5-turbo-128k")
            .setConfigItems(model -> new ConfigItem[]{
                    ConfigItem.ofDefaultModel(false, "默认大模型为：" + model.getDefaultModel()),
                    ConfigItem.ofApiKey(true, null),
                    ConfigItem.ofApiUrl(false, null)
            });


    /**
     * moonshot大模型
     */
    public static final AIModel MOONSHOT = new AIModel(SN_MOONSHOT, "Moonshot",  MoonshotAIImpl.INSTANCE, "moonshot-v1-128k").setImageInput(true)
            .setConfigItems(model -> new ConfigItem[] {
                    ConfigItem.ofDefaultModel(false, "默认大模型为：" + model.getDefaultModel()),
                    ConfigItem.ofApiKey(true, null),
                    ConfigItem.ofApiUrl(false, null)
            });


    /**
     * 本地大模型，目前仅支持按照我们的规范部署的本地大模型
     */
    public static final AIModel LOCAL_MODEL = new AIModel(SN_LOCAL_MODEL, "本地自定义大模型",  LocalAIImpl.INSTANCE, "Baichuan2-13B-Chat")
            .setConfigItems(model -> new ConfigItem[] {
                    ConfigItem.ofApiUrl(true, null)
            }).setIsLocal(true);

    /**
     * Ollama
     */
    public static final AIModel OLLAMA = new AIModel(SN_OLLAMA,  "Ollama", OllamaAIImpl.INSTANCE, null).setImageInput(true)
            .setConfigItems(model -> new ConfigItem[]{
                    ConfigItem.ofDefaultModel(true, null),
                    ConfigItem.ofApiUrl(true, "apiUrl一般为http://{ollama所在服务器ip}:11434/api/chat")
            }).setIsLocal(true);

    /**
     * 硅基流动
     */
    public static final AIModel SILICONFLOW = new AIModel(SN_SILICONFLOW, "硅基流动",  SiliconflowAIImpl.INSTANCE, null)
            .setImageInput(true).setConfigItems(model -> new ConfigItem[]{
                    ConfigItem.ofDefaultModel(true, null),
                    ConfigItem.ofApiKey(true, null),
                    ConfigItem.ofApiUrl(false, null)
            });
    /**
     * LM Studio
     */
    public static final AIModel LM_STUDIO = new AIModel(SN_LM_STUDIO, "LM Studio",  LMStudioAIImpl.INSTANCE, null)
            .setConfigItems(model -> new ConfigItem[]{
                    ConfigItem.ofDefaultModel(true, null),
                    ConfigItem.ofApiUrl(true, "apiUrl一般为http://{LM Studio所在服务器ip}:1234/v1/chat/completions")
            }).setIsLocal(true);

    /**
     * vLLM
     */
    public static final AIModel vLLM = new AIModel(SN_VLLM,  "vLLM", VLLMAIImpl.INSTANCE, null).setImageInput(true)
            .setConfigItems(model -> new ConfigItem[]{
                    ConfigItem.ofDefaultModel(true, null),
                    ConfigItem.ofApiUrl(true, "apiUrl一般为http://{vLLM所在服务器ip}:8000/v1/chat/completions")
            }).setIsLocal(true);


    public static final AIModel GLM = new AIModel(SN_GLM,  "智谱清言", GLM4AIImpl.INSTANCE, "GLM-4-Air").setImageInput(true)
            .setConfigItems(model -> new ConfigItem[] {
                    ConfigItem.ofDefaultModel(false, "默认大模型为：" + model.getDefaultModel()),
                    ConfigItem.ofApiKey(true, null),
                    ConfigItem.ofApiUrl(false, null)
            });


    ;


    private String sn;

    private String name;

    /**
     * 该模型对应的ai事件处理器
     */
    private AIEventProcessor aiEventProcessor;


    private String defaultModel;


    /**
     * 文本输入
     */
    private boolean textInput = true;

    /**
     * 图片输入
     */
    private boolean imageInput = false;

    /**
     * 声音输入
     */
    private boolean audioInput = false;

    /**
     * 视频输入
     */
    private boolean videoInput = false;

    /**
     * 文本输出
     */
    private boolean textOutput = true;

    /**
     * 图片输出
     */
    private boolean imageOutput = false;

    /**
     * 声音输出
     */
    private boolean audioOutput = false;

    /**
     * 视频输出
     */
    private boolean videoOutput = false;

    private ConfigItem[] configItems;

    /**
     * 是否是本地大模型
     */
    private boolean isLocal = false;

    /**
     * ai模型
     *
     * @param sn             模型名称
     * @param aiEventProcessor 该模型对应的ai事件处理器
     * @param defaultModel     如果ai事件通过该模型处理，默认使用哪个具体的型号，比如 'Baichuan2-Turbo-192k'、'gpt-3.5-turbo-0613'
     */
    public AIModel(String sn, String name, AIEventProcessor aiEventProcessor, String defaultModel) {
        this.sn = sn;
        this.name = name;
        this.aiEventProcessor = aiEventProcessor;
        this.defaultModel = defaultModel;

    }

    public boolean getIsLocal() {
        return isLocal;
    }

    public AIModel setIsLocal(boolean local) {
        this.isLocal = local;
        return this;
    }

    public String getSn() {
        return sn;
    }

    public String getName() {
        return name;
    }

    public String getDefaultModel() {

        return defaultModel;
    }


    public AIEventProcessor getAIEventProcessor() {
        return aiEventProcessor;
    }

    public boolean isTextInput() {
        return textInput;
    }

    public AIModel setTextInput(boolean textInput) {
        this.textInput = textInput;
        return this;
    }

    public boolean isImageInput() {
        return imageInput;
    }

    public AIModel setImageInput(boolean imageInput) {
        this.imageInput = imageInput;
        return this;
    }

    public boolean isAudioInput() {
        return audioInput;
    }

    public AIModel setAudioInput(boolean audioInput) {
        this.audioInput = audioInput;
        return this;
    }

    public boolean isVideoInput() {
        return videoInput;
    }

    public AIModel setVideoInput(boolean videoInput) {
        this.videoInput = videoInput;
        return this;
    }

    public boolean isTextOutput() {
        return textOutput;
    }

    public AIModel setTextOutput(boolean textOutput) {
        this.textOutput = textOutput;
        return this;
    }

    public boolean isImageOutput() {
        return imageOutput;
    }

    public AIModel setImageOutput(boolean imageOutput) {
        this.imageOutput = imageOutput;
        return this;
    }

    public boolean isAudioOutput() {
        return audioOutput;
    }

    public AIModel setAudioOutput(boolean audioOutput) {
        this.audioOutput = audioOutput;
        return this;
    }

    public boolean isVideoOutput() {
        return videoOutput;
    }

    public AIModel setVideoOutput(boolean videoOutput) {
        this.videoOutput = videoOutput;
        return this;
    }

    public ConfigItem[] getConfigItems() {
        return configItems;
    }

    /**
     * 不对外暴露
     * @return
     */
    private AIModel setConfigItems(Function<AIModel, ConfigItem[]> handler) {
        this.configItems = handler.apply(this);
        return this;
    }

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private static class ConfigItem {

        /**
         * 默认大模型的配置项
         *
         * @param required
         * @param remark
         * @return
         */
        static ConfigItem ofDefaultModel(boolean required, String remark) {
            return new ConfigItem("defaultModel", required, remark);
        }

        /**
         * api_key配置项
         *
         * @param required
         * @param remark
         * @return
         */
        static ConfigItem ofApiKey(boolean required, String remark) {
            return new ConfigItem("apiKey", required, remark);
        }

        /**
         * api_key配置项
         *
         * @param required
         * @param remark
         * @return
         */
        static ConfigItem ofApiSecret(boolean required, String remark) {
            return new ConfigItem("apiSecret", required, remark);
        }

        /**
         * api_url配置项
         *
         * @param required
         * @param remark
         * @return
         */
        static ConfigItem ofApiUrl(boolean required, String remark) {
            return new ConfigItem("apiUrl", required, remark);
        }


        /**
         * 配置字段
         */
        private String field;

        /**
         * 是否必填
         */
        private boolean required;

        /**
         * 备注
         */
        private String remark;

        public ConfigItem(String field, boolean required, String remark) {
            this.field = field;
            this.required = required;
            this.remark = remark;
        }

        public String getField() {
            return field;
        }

        public boolean isRequired() {
            return required;
        }

        public String getRemark() {
            return remark;
        }
    }


}
